﻿using System.Collections.Generic;
using System.Linq;
using Godot;
using GoGameClient.script.tool;

namespace GoGameClient.script.map;

public class Terrain
{
    private List<Vector2I> AStartPosition { get; set; }
    public Vector2I CurrentV { get; set; }
    public Vector2I TargetV { get; set; }
    private Vector2I RouteV { get; set; }

    public AStarGrid2D AStarGrid2D { get; set; }


    private Vector2I FindPosition(Vector2 currentV)
    {
        var length = 1;
        while (length < 300)
        {
            for (double angle = 0; angle < 6; angle += 0.5f)
            {
                var position = (Vector2I)Vector2Util.GetToPosition(currentV, length, angle);
                if (!AStarGrid2D.IsPointSolid(position))
                {
                    return position;
                }
            }

            length += 1;
        }

        return new Vector2I(0, 0);
    }

    public void UpdateLinePosition()
    {
        if (AStartPosition == null)
        {
            return;
        }

        switch (AStartPosition.Count)
        {
            case 0:
                AStartPosition = null;
                return;
            case <= 1:
                RouteV = AStartPosition[^1];
                return;
        }

        for (var i = 1; i < AStartPosition.Count - 1; i++)
        {
            if (IsLine(AStartPosition[1], AStartPosition[i]))
            {
                AStartPosition.RemoveAt(i);
            }
            else
            {
                break;
            }
        }

        RouteV = AStartPosition[0];
        AStartPosition.RemoveAt(0);
    }

    public Vector2I GetCurrentPosition()
    {
        return RouteV;
    }


    public void StartPathRoute()
    {
        if (SimplRoute()) return;
        InitAStartRoute();
        RemoveRangePosition();
        UpdateLinePosition();
    }

    private bool SimplRoute()
    {
        if (!IsLine(CurrentV, TargetV)) return false;
        AStartPosition = null;
        RouteV = TargetV;
        return true;
    }

    public bool IsMove(Vector2I vector2I)
    {
        if (vector2I.X < 0 || vector2I.Y < 0) return false;
        if (vector2I.X > AStarGrid2D.Region.Size.X || vector2I.Y > AStarGrid2D.Region.Size.Y) return false;
        return AStarGrid2D.IsInBoundsv(vector2I);
    }

    private void InitAStartRoute()
    {
        // 点击到障碍
        if (AStarGrid2D.IsPointSolid(TargetV))
        {
            var findPosition = FindPosition(TargetV);
            TargetV = findPosition != new Vector2I(0, 0) ? findPosition : CurrentV;
        }

        // 角色本身在障碍里
        if (AStarGrid2D.IsPointSolid(CurrentV))
        {
            var findPosition = FindPosition(CurrentV);
            CurrentV = findPosition != new Vector2I(0, 0) ? findPosition : CurrentV;
        }

        AStartPosition = AStarGrid2D.GetPointPath(CurrentV, TargetV).ToList()
            .Select((item) => new Vector2I((int)item.X, (int)item.Y)).ToList();
    }

    private void RemoveRangePosition()
    {
        if (AStartPosition == null)
        {
            return;
        }

        if (AStartPosition.Count <= 1)
        {
            return;
        }

        for (var i = 0; i < AStartPosition.Count - 1; i++)
        {
            if (Vector2Util.GetLength(CurrentV, AStartPosition[i]) <= 2)
            {
                AStartPosition.RemoveAt(i);
            }
        }
    }

    private bool IsLine(Vector2 currentV, Vector2 targetV)
    {
        var length = Vector2Util.GetLength(currentV, targetV) - 1.5;
        for (var i = length; i > 0; i -= 0.5)
        {
            var position = (Vector2I)Vector2Util.GetToPosition(currentV, targetV, i);
            if (AStarGrid2D.IsPointSolid(position))
            {
                return false;
            }
        }

        return true;
    }
}